#ifndef __M_THREADPOOL_H__
#define __M_THREADPOOL_H__
#include<iostream>
#include<vector>
#include<functional>
#include<mutex>
#include<atomic>
#include<thread>
#include<memory>
#include<future>
#include<condition_variable>
class threadpool{
    using Functor=std::function<void(void)>;
    
    public:
    using ptr=std::shared_ptr<threadpool>;
    threadpool(int thread_count=1):_stop(false){
        for(int i=0;i<thread_count;i++)
        {
            _threadpool.emplace_back(&threadpool::entry,this);//内部自己申请空间，构造我们的对象，我们的对象是线程
        }
    }
    ~threadpool()
    {
        
            stop();
     }
    //首先用户需要传入的是一个函数，和参数
    //push函数内部会将这个函数，封装成一个异步任务（packge_task）
    //使用lambda形成一个可调用对象（内部异步执行任务）,抛入到任务池，工作线程取出执行
    template<typename F,typename ...Args>
    auto push(F&&func,Args&&...args)->std::future<decltype(func(args...))>
    {
        //1、构造packge_task对象
        using func_type=decltype(func(args...));
        auto fun=std::bind(std::forward<F>(func),std::forward<Args>(args)...);//我们并不知道用户传入的参数，但我们知道bind后没有参数的，已经绑定进去的
        //auto task=std::packaged_task<func_type>(fun)//这是一个局部变量会在线程结束后销毁;故需要在堆空间上new
        auto task=std::make_shared<std::packaged_task<func_type()>>(fun);
        std::future<func_type> fu=task->get_future();
        //2、构造一个lambda匿名对象抛入到任务池中
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _taskpool.push_back( [task](){(*task)();} );
            _cv.notify_one();
        }
        return fu;
    }
    void stop()
    {
        if(_stop==true)return;
        _stop=true;
        _cv.notify_all();
        for(auto&thread:_threadpool)
        {
            thread.join();
        }
    }
    private:
    //线程进入入口，线程不断从线程池中取出任务执行
    void entry()
    {
        while(!_stop)
        {
                //加锁
            std::vector<Functor> tmp_taskpool;
            {
                //从线程池中取出任务
                std::unique_lock<std::mutex> lock(_mutex);
                _cv.wait(lock,[this](){return _stop||!_taskpool.empty();});
                tmp_taskpool.swap(_taskpool);
            }
            //执行任务
            for(auto&task:tmp_taskpool)
            {
                task();
            }
        }
        
    }
    private:
    std::mutex _mutex;
    std::condition_variable _cv;
    std::vector<Functor> _taskpool;//任务池
    std::vector<std::thread> _threadpool;//线程池
    std::atomic<bool> _stop;//线程池结束标志
};
#endif